using TMPro;
using UnityEngine;

/// <summary>
/// Game 类是扫雷游戏的主控制器
/// </summary>
public class Game : MonoBehaviour
{
    [SerializeField]
    TextMeshPro minesText;                        // UI 文本组件，用于显示剩余地雷数量或游戏结果

    [SerializeField]
    Material material;                            // 用于渲染格子的材质

    [SerializeField]
    Mesh mesh;                                    // 用于渲染格子的网格模型

    [SerializeField, Min(1)]
    int
        rows = 8,                                 // 游戏网格的行数
        columns = 21,                             // 游戏网格的列数
        mines = 30;                               // 地雷的总数量

    Grid grid;                                    // 游戏网格数据模型，管理每个格子的状态、地雷位置等信息
    GridVisualization visualization;              // 网格的可视化组件，负责格子的渲染与绘制

    int markedSureCount;                          // 当前被“确定标记”为地雷的格子数量

    bool isGameOver;                              // 标记当前游戏是否已经结束（胜利或失败）
    
    void OnEnable ()
    {
        // 初始化网格数据，设置行数和列数
        grid.Initialize(rows, columns);

        // 初始化网格的可视化部分，传入网格数据、材质和网格模型
        visualization.Initialize(grid, material, mesh);

        // 开始一场新游戏
        StartNewGame();
    }

    /// <summary>
    /// 开始新的一轮扫雷游戏，重置游戏状态
    /// </summary>
    void StartNewGame ()
    {
        // 重置游戏为未结束状态
        isGameOver = false;

        // 确保地雷数量不超过总格子数
        mines = Mathf.Min(mines, grid.CellCount);

        // 更新 UI 上显示的地雷数量
        minesText.SetText("{0}", mines);

        // 重置“确定标记”的地雷数量为 0
        markedSureCount = 0;

        // 在网格中随机布置指定数量的地雷
        grid.PlaceMines(mines);
    }


    void OnDisable ()
    {
        grid.Dispose(); // 释放网格数据占用的资源
        visualization.Dispose(); // 释放可视化组件占用的资源
    }
    
    void Update ()
    {
        // 如果当前网格的行列数与设定不一致（可能被外部修改），则重新初始化整个游戏
        if (grid.Rows != rows || grid.Columns != columns)
        {
            OnDisable();
            OnEnable();
        }

        // 执行用户操作（点击或标记）
        PerformAction();

        // 更新并绘制网格的可视化表现
        visualization.Draw();
    }

    /// <summary>
    /// 处理玩家的输入操作，包括左键翻开格子和右键标记格子
    /// </summary>
    void PerformAction ()
    {
        // 检测是否按下鼠标左键（用于翻开格子）
        bool revealAction = Input.GetMouseButtonDown(0);

        // 检测是否按下鼠标右键（用于标记/取消标记格子）
        bool markAction = Input.GetMouseButtonDown(1);

        // 如果发生了左键或右键操作，并且成功获取到了鼠标点击对应的格子索引
        if (
            (revealAction || markAction) &&
            visualization.TryGetHitCellIndex(Camera.main.ScreenPointToRay(Input.mousePosition), out int cellIndex)
        )
        {
            // 如果游戏已经结束，点击任意格子都会重新开始新游戏
            if (isGameOver)
            {
                StartNewGame();
            }

            if (revealAction)
            {
                // 如果是左键点击，执行翻开格子的逻辑
                DoRevealAction(cellIndex);
            }
            else
            {
                // 如果是右键点击，执行标记/取消标记格子的逻辑
                DoMarkAction(cellIndex);
            }
        }
    }

    /// <summary>
    /// 处理标记格子的逻辑（右键操作）
    /// </summary>
    void DoMarkAction (int cellIndex)
    {
        // 获取当前格子的状态
        CellState state = grid[cellIndex];

        // 如果格子已经被翻开，则不允许标记，直接返回
        if (state.Is(CellState.Revealed))
        {
            return;
        }
        
        if (state.IsNot(CellState.Marked)) // 如果当前格子没有被标记为“确定地雷”
        {
            // 将格子标记为“确定地雷”（MarkedSure），并增加标记计数
            grid[cellIndex] = state.With(CellState.MarkedSure);
            markedSureCount += 1;
        }
        else if (state.Is(CellState.MarkedSure)) // 如果当前格子已经是“确定地雷”
        {
            // 取消“确定地雷”标记，改为“不确定标记”（MarkedUnsure），并减少标记计数
            grid[cellIndex] = state.Without(CellState.MarkedSure).With(CellState.MarkedUnsure);
            markedSureCount -= 1;
        }
        else // 如果当前是“不确定标记”状态
        {
            // 取消所有标记
            grid[cellIndex] = state.Without(CellState.MarkedUnsure);
        }

        // 更新 UI 上显示的剩余地雷数量（总地雷数 - 已确定标记的地雷数）
        minesText.SetText("{0}", mines - markedSureCount);
    }

    /// <summary>
    /// 处理翻开格子的逻辑（左键操作）
    /// </summary>
    void DoRevealAction (int cellIndex)
    {
        // 获取当前格子的状态
        CellState state = grid[cellIndex];

        // 如果格子已经被标记或者已经翻开，则不允许再次操作，直接返回
        if (state.Is(CellState.MarkedOrRevealed))
        {
            return;
        }

        // 执行翻开格子的操作
        grid.Reveal(cellIndex);

        if (state.Is(CellState.Mine)) // 如果翻开的格子是地雷
        {
            isGameOver = true;                     // 游戏结束，玩家失败
            minesText.SetText("FAILURE");          // 更新 UI 显示失败信息
            grid.RevealMinesAndMistakes();         // 显示所有地雷和错误标记的格子
        }
        else if (grid.HiddenCellCount == mines) // 如果剩下的未翻开格子数等于地雷总数，说明全部安全格子已被翻开，玩家获胜
        {
            isGameOver = true;                     // 游戏结束，玩家胜利
            minesText.SetText("SUCCESS");          // 更新 UI 显示成功信息
        }
    }
}